// Created by dcl on 2024/10/16.
// Description:
//      日志模块
#ifndef LOGGER_H
#define LOGGER_H

#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <mutex>

class Logger
{
public:
    // 日志级别定义 DEBUG 0  < INFO 1 < WARNING 2 < ERROR 3  < ALERT 4
    enum LogLevel
    {
        DEBUG = 0,
        INFO,
        WARNING,
        ERROR,
        ALERT
    };

    // 获取Logger实例
    static Logger &getInstance()
    {
        static Logger instance; // 静态局部变量，确保单例模式
        return instance;
    }

    // 设置日志文件路径, 静态成员函数, 可以在不创建Logger实例的情况下调用，调用静态成员变量
    static void InitLogger(const std::string &filePath)
    {
        logFile = filePath;
        getInstance().openLogFile(); // 初始化打开日志文件
    }

    // 设置日志级别
    static void setLogLevel(int level)
    {
        if (level >= static_cast<int>(LogLevel::DEBUG) && level <= static_cast<int>(LogLevel::ALERT)) // 判断是否为有效的日志级别
        {
            logLevel = static_cast<LogLevel>(level);
        }
        else
        {
            std::cout << "Invalid log level." << std::endl;
        }
    }

    // 判断日志级别是否需要记录
    bool isLogLevelEnabled(int level)
    {
        return level >= static_cast<int>(logLevel);
    }

    // 记录日志信息到文件
    void logMessage(LogLevel level, const std::string &message)
    {
        if (!isLogLevelEnabled(level))
        {
            return; // 如果日志级别低于当前设置的日志级别，则不记录
        }

        std::lock_guard<std::mutex> guard(logMutex); // 确保线程安全

        if (logStream.is_open())
        {
            logStream << getCurrentTime() << " " << logLevelToString(level) << ": " << message << std::endl;
        }
        else
        {
            std::cerr << "Unable to open log file: " << logFile << std::endl;
        }
    }

    // 输出日志内容到控制台
    void printLog(const std::string &filterStartDate = "")
    {
        std::ifstream logStream(logFile);

        if (logStream.is_open())
        {
            std::string line;
            while (std::getline(logStream, line))
            {
                // 提取每行日志的日期
                int index_date = line.find(" ");
                std::string date = line.substr(0, index_date);

                // 如果提供了日期过滤条件,且当前行日志日期小于过滤日期，则不输出
                if (!filterStartDate.empty() && date < filterStartDate)
                {
                    continue;
                }

                // 提取每行日志的级别
                int index_end = line.rfind(":");
                int index_start = line.rfind(" ", index_end - 1);
                std::string level = line.substr(index_start + 1, index_end - index_start - 1);

                // 根据当前级别判断level对应的级别是否输出
                if (!isLogLevelEnabled(static_cast<int>(stringToLogLevel(level)))) // 如果日志级别低于当前设置的日志级别，则不输出
                {
                    continue;
                }

                // 根据日志级别设置输出颜色
                if (level == "Debug")
                    std::cout << "\033[34m"; // 蓝色
                else if (level == "Info")
                    std::cout << "\033[32m"; // 绿色
                else if (level == "Warning")
                    std::cout << "\033[33m"; // 黄色
                else if (level == "Error")
                    std::cout << "\033[31m"; // 红色
                else if (level == "Alert")
                    std::cout << "\033[35m"; // 紫色
                else
                    std::cout << "\033[0m"; // 默认颜色

                std::cout << line << std::endl;
            }
            logStream.close();
        }
        else
        {
            std::cerr << "Unable to open log file: " << logFile << std::endl;
        }
    }

    ~Logger()
    {
        if (logStream.is_open())
        {
            logStream.close();
        }
    }

    // 禁用拷贝构造函数和赋值运算符
    Logger(const Logger &) = delete;
    Logger &operator=(const Logger &) = delete;

private:
    Logger(){}

    void openLogFile()
    {
        logStream.open(logFile, std::ios_base::app); // 追加模式，不覆盖已有日志
        if (!logStream.is_open())
        {
            std::cerr << "Unable to open log file: " << logFile << std::endl;
        }
    }

    // 获取当前时间，格式为YYYY-MM-DD HH:MM:SS
    std::string getCurrentTime()
    {
        time_t now = time(0); // time_t是一个长整型
        tm *localtm = localtime(&now);
        char buf[20];
        strftime(buf, sizeof(buf), "%Y%m%d %H:%M:%S", localtm);
        return std::string(buf);
    }

    // 日志级别转换为字符串
    std::string logLevelToString(LogLevel level)
    {
        switch (level)
        {
        case DEBUG:
            return "Debug";
        case INFO:
            return "Info";
        case WARNING:
            return "Warning";
        case ERROR:
            return "Error";
        case ALERT:
            return "Alert";
        default:
            return "Unknown";
        }
    }

    // 字符串转换为日志级别
    LogLevel stringToLogLevel(const std::string &level)
    {
        if (level == "Debug")
            return DEBUG;
        else if (level == "Info")
            return INFO;
        else if (level == "Warning")
            return WARNING;
        else if (level == "Error")
            return ERROR;
        else if (level == "Alert")
            return ALERT;
        else
            return INFO;
    }

    static std::string logFile; // 静态成员变量，日志文件路径
    static LogLevel logLevel;   // 当前日志级别
    std::ofstream logStream;    // 文件流，用于记录日志
    std::mutex logMutex;        // 线程安全
};

// 静态成员变量类外初始化
std::string Logger::logFile = "default_log.txt";
Logger::LogLevel Logger::logLevel = Logger::INFO;

#define LOG(level, message) Logger::getInstance().logMessage(level, message) // 定义LOG宏，方便调用
#define PRINT_LOG(StartDate) Logger::getInstance().printLog(StartDate)       // 定义PRINT_LOG宏，方便调用

#endif // LOGGER_H